
#include <BFont>
#include <BPainter>
#include <BFocusEvent>
#include <BMouseEvent>

#include <BMenu>
#include "member_BMenu.h"
#include "member_BAction.h"

using namespace BWE;

#define member					(*(member_BMenu*)_ptr)
#define member_allocate()		_ptr = new member_BMenu(this)
#define member_release()		delete (member_BMenu*)_ptr

BMenu::BMenu(BWidget* parent) : BWidget(parent)
{
	member_allocate();
	this->hide();
}
BMenu::BMenu(const BString& name, BWidget* parent) : BWidget(parent)
{
	member_allocate();
	this->hide();
	this->setName(name);
}
BMenu::~BMenu()
{
	member_release();
}

void BMenu::addAction(BAction* action)
{
	if(action)
	{
		member.connect(action, Signal_TextChanged, &member_BMenu::procTextChanged);
		member.actions.append(action);
		member.adjustRects();
	}
}
void BMenu::addAction(const BString& actionText)
{
	BAction* action = new BAction(actionText);
	addAction(action);
}

void BMenu::insertAction(int pos, BAction* action)
{
	if(action && member.actions.insert(pos, action))
	{
		member.connect(action, Signal_TextChanged, &member_BMenu::procTextChanged);
		member.adjustRects();
	}
}
void BMenu::insertAction(int pos, const BString& actionText)
{
	BAction* action = new BAction(actionText);
	insertAction(pos, action);
}

void BMenu::removeAction(BAction* action)
{
	if(action && member.actions.contain(action))
	{
		member.disconnect(action);
		member.actions.remove(action);
		member.adjustRects();
	}
}
void BMenu::removeAction(const BString& actionText)
{
	for (int i = 0; i < member.actions.size(); i++)
	{
		BAction* action = member.actions[i].action;
		if (action->text() == actionText)
		{
			member.disconnect(action);
			member.actions.remove(i);
			i--;
		}
	}
}

int BMenu::actionCount() const
{
	return member.actions.size();
}
BAction* BMenu::action(int index)
{
	return member.actions[index].action;
}
const BAction* BMenu::action(int index) const
{
	return member.actions[index].action;
}

void BMenu::setSpace(int space)
{
	if(member.space != space)
	{
		member.space = space;
		member.adjustRects();
	}
}
int BMenu::space() const
{
	return member.space;
}

void BMenu::showEvent(const BEvent& showEvent)
{
	this->setFocus(true);
}
void BMenu::focusEvent(const BFocusEvent& focusEvent)
{
	if(focusEvent.focus() == Focus_Out)
		this->hide();
}

void BMenu::paintEvent(const BEvent& event)
{
	member.adjustRects();
	BWidget::paintEvent(event);

	BPainter painter(this);
	painter.setColor(BColor(128, 128, 128, 128));
	painter.drawRect(0, 0, width(), height());

	painter.setColor(BColor(210, 210, 210, 200));
	painter.fillRect(1, 1, width()-2, height()-2);

	for(int i = 0; i < member.actions.size(); i++)
	{
		BAction* action = member.actions[i].action.ptr();
		BRect& rect = member.actions[i].rect;

		StyleRole colorRole = Color_Disable;
		if (action->able())
		{
			colorRole = Color_Normal;
			if (action->checked())
				colorRole = Color_Checked;
			if (member.hoverIndex == i)
			{
				if (member.pressed)
					colorRole = Color_Pressed;
			}
		}
		if (painter.setColor(colorRole))
		{
			painter.fillRect(rect);
			painter.drawRect(rect);
		}
		if (action->icon())
		{
			const BIcon* icon = action->icon();
			State state = State_Normal;
			if (action->checked())
				state = State_Checked;
			if (!action->able())
				state = State_Disable;
			painter.drawImage(rect.x(), rect.y(), rect.height(), rect.height(), icon->image(state));
		}
		if (painter.setColor(Color_Text))
		{
			painter.drawText(rect, action->text());
		}
	}
}
void BMenu::resizeEvent(const BEvent& event)
{
	member.adjustRects();
}

void BMenu::mouseEnterEvent(const BMouseEvent& mouseEvent)
{
	member.pressed = false;
	member.hoverIndex = -1;
}
void BMenu::mouseLeaveEvent(const BMouseEvent& mouseEvent)
{
	member.pressed = false;
	if (member.hoverIndex != -1)
	{
		member.hoverIndex = -1;
		fresh();
	}
}

void BMenu::mousePressEvent(const BMouseEvent& mouseEvent)
{
	member.pressed = true;
	fresh();
}
void BMenu::mouseReleaseEvent(const BMouseEvent& mouseEvent)
{
	if(member.hoverIndex >= 0)
	{
		this->hide();
		BAction* action = member.actions[member.hoverIndex].action.ptr();
		action->trigger();
		emit(Signal_Trigger, action);
	}
	this->setFocus(false);
	member.pressed = false;
	fresh();
}
void BMenu::mouseMoveEvent(const BMouseEvent& mouseEvent)
{
	int hoverIndex = member.hoverIndex;
	BPoint pos = mouseEvent.pos();
	for (int i = 0; i < member.actions.size(); i++)
	{
		BRect& actRect = member.actions[i].rect;
		if (actRect.contain(pos))
		{
			hoverIndex = i;
			break;
		}
	}
	if (member.hoverIndex != hoverIndex)
	{
		member.hoverIndex = hoverIndex;
		BAction* action = member.actions[hoverIndex].action;
		emit(Signal_Hovered, action);
		fresh();
	}
}

